package cn.biplam.common.wrapper;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 实现了双向查询的map容器
 * <ul>用法:
 *   <li>往容器中放入单个键值对: put(key,value)
 *   <li>往容器中放入多个键值对: putAll(map)
 *   <li>根据键获取值: getByKey(key)
 *   <li>根据值获取键: getByValue(value)
 * <ul>
 * @author XiaoRuxing Nov 2, 200911:09:31 AM
 * @version 1.0
 */
public class KvMap<K,V> implements Serializable,Iterable<Entry<K, V>>{
	
	private static final long serialVersionUID = 6491682054896479683L;//类序列号
	private  HashMap<K, V> mPositiveMap;//映射Map
	private Iterator<K> itKey;//上次getByValue得到的键的迭代器
	private int size;//Map包含的键值对个数

	@SuppressWarnings("unchecked")
	public KvMap(){
		this(16, 0.75f);
	}

	public KvMap(int initialCapacity){
		this(initialCapacity, 0.75f);
	}

	public KvMap(int initialCapacity,
			float loadFactor){
		mPositiveMap=new HashMap<K, V>(initialCapacity,loadFactor);
	}

	/**
	 * 关联指定值与指定键
	 * @param key   键
	 * @param value 值
	 */
	public void put(K key,V value) throws ErrorMessage{		
		/** 如果键为空，抛出四级异常 */
		if(key==null){
			throw new ErrorMessage("空指针异常");
		}
		mPositiveMap.put(key, value);
		size=mPositiveMap.size();
	} 

	/**
	 * 将多个键值对插入到KvMap
	 * @param values 多个键值对
	 * @throws ErrorMessage
	 */
	public void putAll(KvMap<K, V> values) throws ErrorMessage{
		Iterator<Map.Entry<K, V>> elements=values.getIterator();
		Map.Entry<K, V> element=null;
		while(elements.hasNext()){
			element=elements.next();
			put(element.getKey(),element.getValue());
		}
	}
	
	/**
	 * 	返回键对应的值<br>
	 * 如果不存在键对应的值返回null
	 * @param key
	 * @return 键对应的值
	 */
	public V getByKey(K key){
		return mPositiveMap.get(key);
	}

	/**
	 * 	返回值映射的键,如果值映射的键有多个则将键放入迭代器中，并返回迭代器的第一个元素
	 * @param value
	 * @return 值对应的键
	 */
	public K getByValue(V value){
		
		/** 取得值对应迭代器 */
		ArrayList<K> aKeys=null;		
		aKeys=getKeyIteByValue(value);		
		itKey=aKeys.iterator();			
		
		/** 返回迭代器第一个值 */
		if(itKey.hasNext()){
			return (K)itKey.next();
		}else{
			return null;			
		}		
	}  	

	/**
	 * 返回上一次getByValue得到的键迭代器的下一个元素,必须在getByValue之后使用此方法,否则返回异常
	 * @return 迭代器的下一个元素
	 */
	public K getNextKeyByValue() throws ErrorMessage{
		
		/** 如果执行之前未调用getByValue方法，抛出四级异常 */
		if(itKey==null){
			throw new ErrorMessage("执行顺序错误,未调用getByValue.");
		}
		
		if(itKey.hasNext()){
			return (K)itKey.next();			
		}else{
			return null;
		}
	}

	/**
	 * 返回getByValue得到的键迭代器是否有下一个元素,必须在getByValue之后使用此方法,否则返回异常
	 * @return 迭代器是否存在元素
	 */
	public boolean haveNextKeyByValue() throws ErrorMessage{
		
		/** 如果执行之前未调用getByValue方法，抛出四级异常 */
		if(itKey==null){
			throw new ErrorMessage("执行顺序错误,未调用getByValue.");
		}
		return itKey.hasNext();
	}

	/**
	 * 查询值对应的键，将所有该值对应的键放入容器中
	 * @param value 值
	 * @return 返回值对应的键
	 */
	public final ArrayList<K> getKeyIteByValue(V value){
		
		ArrayList<K> alKeys=new ArrayList<K>();
		/** 取得迭代器 */
		Iterator<Map.Entry<K,V>> ite=mPositiveMap.entrySet().iterator();
		
		/** 遍历迭代器，如果值等于被查询值，则保存值对应键 */
		while(ite.hasNext()){
			Map.Entry<K,V> e=(Map.Entry<K,V>)ite.next();
			Object v=value;
			if(e.getValue()==null){
				if(e.getValue()==value){
					alKeys.add(e.getKey());
				}
			}else{
				if(e.getValue().equals(v)){
					alKeys.add(e.getKey());
				}
			}
		}
		return alKeys;
	}

	/**
	 * 删除指定键的映射关系
	 * @param key 键
	 */
	public void removeByKey(K key){
		mPositiveMap.remove(key);
		size=mPositiveMap.size();
	}

	/**
	 * 清空KvMap
	 */
	public void clear(){
		mPositiveMap.clear();
	}

	/**
	 * 返回KvMap的键值对个数 
	 * @return
	 */
	public int size(){
		return size;
	}

	/**
	 * 返回是否包含指定键的键值对
	 * @param key
	 * @return 返回是否包含指定键的键值对
	 */
	public boolean containsKey(K key){
		return mPositiveMap.containsKey(key);
	}

	/**
	 * 返回是否包含指定值的键值对
	 * @param value
	 * @return 返回是否包含指定值的键值对
	 */
	public boolean containsValue(V value){
		return mPositiveMap.containsValue(value);
	}

	/**
	 * 返回映射包的迭代器
	 * @return 映射包的迭代器
	 */
	public Iterator<Map.Entry<K, V>> getIterator(){
		return mPositiveMap.entrySet().iterator();
	}
	
	/**
	 * 返回此KvMap的字符串表示形式,相邻的映射关系是用逗号加回车分隔
	 * @return 映射的字符串表示形式
	 */
	public String toString(){

		Iterator<Map.Entry<K,V>> ite=null;
		StringBuilder sb=null;
		Entry<K,V> ent=null;
		
		ite=getIterator();
		sb=new StringBuilder();
		
		/** head */
		if(ite.hasNext()){
			ent=ite.next();
			process(sb,ent);
		}
		
		/** Iterator */
		while(ite.hasNext()){
			sb.append(",\n");
			ent=ite.next();
			process(sb,ent);
		}
		
		/** bottom */
		sb.append("\n");
		
		return sb.toString();
	}
	
	private void process(StringBuilder sb,Entry<K,V> ent){
		sb.append(ent.getKey());
		sb.append("=");
		sb.append(ent.getValue());
	}

	/**
	 * 覆写Iterable方法，返回迭代器
	 * @return	Iterator<Entry<K, V>>
	 */
	public Iterator<Entry<K, V>> iterator() {
		return getIterator();
	}
}
